#include "hash_index.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>

// Hash index creation
hash_index_t* hash_index_create(memory_manager_t* memory_mgr, 
                                uint32_t initial_buckets,
                                double max_load_factor) {
    if (!memory_mgr || initial_buckets == 0 || max_load_factor <= 0.0) {
        return NULL;
    }
    
    hash_index_t* index = malloc(sizeof(hash_index_t));
    if (!index) return NULL;
    
    memset(index, 0, sizeof(hash_index_t));
    
    // Initialize buckets
    index->bucket_count = initial_buckets;
    index->buckets = calloc(initial_buckets, sizeof(hash_bucket_t));
    if (!index->buckets) {
        free(index);
        return NULL;
    }
    
    // Initialize bucket mutexes
    for (uint32_t i = 0; i < initial_buckets; i++) {
        if (pthread_mutex_init(&index->buckets[i].mutex, NULL) != 0) {
            // Cleanup previously initialized mutexes
            for (uint32_t j = 0; j < i; j++) {
                pthread_mutex_destroy(&index->buckets[j].mutex);
            }
            free(index->buckets);
            free(index);
            return NULL;
        }
    }
    
    // Initialize configuration
    index->max_load_factor = max_load_factor;
    index->min_load_factor = HASH_INDEX_MIN_LOAD_FACTOR;
    index->max_chain_length = HASH_INDEX_MAX_CHAIN_LENGTH;
    index->memory_mgr = memory_mgr;
    
    // Initialize thread safety
    if (pthread_rwlock_init(&index->resize_lock, NULL) != 0) {
        for (uint32_t i = 0; i < initial_buckets; i++) {
            pthread_mutex_destroy(&index->buckets[i].mutex);
        }
        free(index->buckets);
        free(index);
        return NULL;
    }
    
    atomic_init(&index->is_resizing, false);
    
    // Initialize hash seed
    index->hash_seed = (uint32_t)time(NULL) ^ (uint32_t)((uintptr_t)index);
    
    return index;
}

void hash_index_destroy(hash_index_t* index) {
    if (!index) return;
    
    // Clear all entries
    hash_index_clear(index);
    
    // Destroy bucket mutexes
    for (uint32_t i = 0; i < index->bucket_count; i++) {
        pthread_mutex_destroy(&index->buckets[i].mutex);
    }
    
    pthread_rwlock_destroy(&index->resize_lock);
    free(index->buckets);
    free(index);
}

// Hash functions
uint32_t hash_function_djb2(const void* key, size_t key_size) {
    const unsigned char* data = (const unsigned char*)key;
    uint32_t hash = 5381;
    
    for (size_t i = 0; i < key_size; i++) {
        hash = ((hash << 5) + hash) + data[i]; // hash * 33 + c
    }
    
    return hash;
}

uint32_t hash_function_fnv1a(const void* key, size_t key_size) {
    const unsigned char* data = (const unsigned char*)key;
    uint32_t hash = 2166136261U; // FNV offset basis for 32-bit
    
    for (size_t i = 0; i < key_size; i++) {
        hash ^= data[i];
        hash *= 16777619U; // FNV prime for 32-bit
    }
    
    return hash;
}

uint32_t hash_function_murmur3(const void* key, size_t key_size, uint32_t seed) {
    const uint8_t* data = (const uint8_t*)key;
    const uint32_t c1 = 0xcc9e2d51;
    const uint32_t c2 = 0x1b873593;
    const uint32_t r1 = 15;
    const uint32_t r2 = 13;
    const uint32_t m = 5;
    const uint32_t n = 0xe6546b64;
    
    uint32_t hash = seed;
    
    const int nblocks = key_size / 4;
    const uint32_t* blocks = (const uint32_t*)data;
    
    for (int i = 0; i < nblocks; i++) {
        uint32_t k = blocks[i];
        k *= c1;
        k = (k << r1) | (k >> (32 - r1));
        k *= c2;
        
        hash ^= k;
        hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
    }
    
    const uint8_t* tail = (const uint8_t*)(data + nblocks * 4);
    uint32_t k1 = 0;
    
    switch (key_size & 3) {
        case 3: k1 ^= tail[2] << 16;
        case 2: k1 ^= tail[1] << 8;
        case 1: k1 ^= tail[0];
            k1 *= c1;
            k1 = (k1 << r1) | (k1 >> (32 - r1));
            k1 *= c2;
            hash ^= k1;
    }
    
    hash ^= key_size;
    hash ^= (hash >> 16);
    hash *= 0x85ebca6b;
    hash ^= (hash >> 13);
    hash *= 0xc2b2ae35;
    hash ^= (hash >> 16);
    
    return hash;
}

uint32_t hash_function(const void* key, size_t key_size, uint32_t seed) {
    return hash_function_murmur3(key, key_size, seed);
}

// Entry operations
hash_entry_t* hash_entry_create(memory_manager_t* memory_mgr,
                               const void* key, size_t key_size,
                               const void* value, size_t value_size,
                               uint32_t hash_value) {
    hash_entry_t* entry = malloc(sizeof(hash_entry_t));
    if (!entry) return NULL;
    
    // Allocate and copy key
    entry->key = malloc(key_size);
    if (!entry->key) {
        free(entry);
        return NULL;
    }
    memcpy(entry->key, key, key_size);
    entry->key_size = key_size;
    
    // Allocate and copy value
    entry->value = malloc(value_size);
    if (!entry->value) {
        free(entry->key);
        free(entry);
        return NULL;
    }
    memcpy(entry->value, value, value_size);
    entry->value_size = value_size;
    
    entry->hash_value = hash_value;
    entry->next = NULL;
    
    return entry;
}

void hash_entry_destroy(hash_entry_t* entry, memory_manager_t* memory_mgr) {
    if (!entry) return;
    
    free(entry->key);
    free(entry->value);
    free(entry);
}

int hash_entry_key_compare(const hash_entry_t* entry, const void* key, size_t key_size) {
    if (entry->key_size != key_size) {
        return (entry->key_size < key_size) ? -1 : 1;
    }
    return memcmp(entry->key, key, key_size);
}

int hash_key_compare(const void* key1, size_t key1_size, 
                    const void* key2, size_t key2_size) {
    if (key1_size != key2_size) {
        return (key1_size < key2_size) ? -1 : 1;
    }
    return memcmp(key1, key2, key1_size);
}

// Bucket operations
hash_entry_t* hash_bucket_find(hash_bucket_t* bucket, const void* key, size_t key_size,
                              uint32_t hash_value) {
    hash_entry_t* entry = bucket->head;
    
    while (entry) {
        if (entry->hash_value == hash_value && 
            hash_entry_key_compare(entry, key, key_size) == 0) {
            return entry;
        }
        entry = entry->next;
    }
    
    return NULL;
}

index_result_t hash_bucket_insert(hash_bucket_t* bucket, hash_entry_t* entry,
                                 memory_manager_t* memory_mgr) {
    // Check if key already exists
    hash_entry_t* existing = hash_bucket_find(bucket, entry->key, entry->key_size, 
                                             entry->hash_value);
    if (existing) {
        return INDEX_ERROR_KEY_EXISTS;
    }
    
    // Insert at head
    entry->next = bucket->head;
    bucket->head = entry;
    bucket->count++;
    
    return INDEX_SUCCESS;
}

index_result_t hash_bucket_delete(hash_bucket_t* bucket, const void* key, size_t key_size,
                                 uint32_t hash_value, memory_manager_t* memory_mgr) {
    hash_entry_t** entry_ptr = &bucket->head;
    
    while (*entry_ptr) {
        hash_entry_t* entry = *entry_ptr;
        if (entry->hash_value == hash_value && 
            hash_entry_key_compare(entry, key, key_size) == 0) {
            *entry_ptr = entry->next;
            hash_entry_destroy(entry, memory_mgr);
            bucket->count--;
            return INDEX_SUCCESS;
        }
        entry_ptr = &entry->next;
    }
    
    return INDEX_ERROR_KEY_NOT_FOUND;
}

// Core operations
index_result_t hash_index_insert(hash_index_t* index, 
                                const void* key, size_t key_size,
                                const void* value, size_t value_size) {
    if (!index || !key || !value || key_size == 0 || value_size == 0) {
        return INDEX_ERROR_INVALID_PARAM;
    }
    
    // Check if resize is needed before insertion
    pthread_rwlock_rdlock(&index->resize_lock);
    
    uint32_t hash_value = hash_function(key, key_size, index->hash_seed);
    uint32_t bucket_index = hash_value % index->bucket_count;
    hash_bucket_t* bucket = &index->buckets[bucket_index];
    
    pthread_mutex_lock(&bucket->mutex);
    
    // Create new entry
    hash_entry_t* entry = hash_entry_create(index->memory_mgr, key, key_size, 
                                           value, value_size, hash_value);
    if (!entry) {
        pthread_mutex_unlock(&bucket->mutex);
        pthread_rwlock_unlock(&index->resize_lock);
        return INDEX_ERROR_OUT_OF_MEMORY;
    }
    
    index_result_t result = hash_bucket_insert(bucket, entry, index->memory_mgr);
    
    if (result == INDEX_SUCCESS) {
        index->entry_count++;
        index->inserts++;
        
        // Check for collisions
        if (bucket->count > 1) {
            index->collisions++;
        }
    } else {
        hash_entry_destroy(entry, index->memory_mgr);
    }
    
    pthread_mutex_unlock(&bucket->mutex);
    pthread_rwlock_unlock(&index->resize_lock);
    
    index->total_operations++;
    
    // Check if resize is needed after successful insertion
    if (result == INDEX_SUCCESS && hash_index_should_resize(index)) {
        // Try to resize (non-blocking)
        if (pthread_rwlock_trywrlock(&index->resize_lock) == 0) {
            if (!atomic_load(&index->is_resizing)) {
                uint32_t new_bucket_count = hash_index_next_bucket_count(index->bucket_count, true);
                hash_index_resize(index, new_bucket_count);
            }
            pthread_rwlock_unlock(&index->resize_lock);
        }
    }
    
    return result;
}

index_result_t hash_index_delete(hash_index_t* index, 
                                const void* key, size_t key_size) {
    if (!index || !key || key_size == 0) {
        return INDEX_ERROR_INVALID_PARAM;
    }
    
    pthread_rwlock_rdlock(&index->resize_lock);
    
    uint32_t hash_value = hash_function(key, key_size, index->hash_seed);
    uint32_t bucket_index = hash_value % index->bucket_count;
    hash_bucket_t* bucket = &index->buckets[bucket_index];
    
    pthread_mutex_lock(&bucket->mutex);
    
    index_result_t result = hash_bucket_delete(bucket, key, key_size, hash_value, 
                                              index->memory_mgr);
    
    if (result == INDEX_SUCCESS) {
        index->entry_count--;
        index->deletes++;
    }
    
    pthread_mutex_unlock(&bucket->mutex);
    pthread_rwlock_unlock(&index->resize_lock);
    
    index->total_operations++;
    
    return result;
}

index_result_t hash_index_update(hash_index_t* index,
                                const void* key, size_t key_size,
                                const void* value, size_t value_size) {
    if (!index || !key || !value || key_size == 0 || value_size == 0) {
        return INDEX_ERROR_INVALID_PARAM;
    }
    
    pthread_rwlock_rdlock(&index->resize_lock);
    
    uint32_t hash_value = hash_function(key, key_size, index->hash_seed);
    uint32_t bucket_index = hash_value % index->bucket_count;
    hash_bucket_t* bucket = &index->buckets[bucket_index];
    
    pthread_mutex_lock(&bucket->mutex);
    
    hash_entry_t* entry = hash_bucket_find(bucket, key, key_size, hash_value);
    if (!entry) {
        pthread_mutex_unlock(&bucket->mutex);
        pthread_rwlock_unlock(&index->resize_lock);
        index->total_operations++;
        return INDEX_ERROR_KEY_NOT_FOUND;
    }
    
    // Reallocate value if size changed
    if (entry->value_size != value_size) {
        void* new_value = realloc(entry->value, value_size);
        if (!new_value) {
            pthread_mutex_unlock(&bucket->mutex);
            pthread_rwlock_unlock(&index->resize_lock);
            index->total_operations++;
            return INDEX_ERROR_OUT_OF_MEMORY;
        }
        entry->value = new_value;
        entry->value_size = value_size;
    }
    
    memcpy(entry->value, value, value_size);
    index->updates++;
    
    pthread_mutex_unlock(&bucket->mutex);
    pthread_rwlock_unlock(&index->resize_lock);
    
    index->total_operations++;
    
    return INDEX_SUCCESS;
}

index_result_t hash_index_search(hash_index_t* index,
                                const void* key, size_t key_size,
                                index_search_result_t* result) {
    if (!index || !key || !result || key_size == 0) {
        return INDEX_ERROR_INVALID_PARAM;
    }
    
    pthread_rwlock_rdlock(&index->resize_lock);
    
    uint32_t hash_value = hash_function(key, key_size, index->hash_seed);
    uint32_t bucket_index = hash_value % index->bucket_count;
    hash_bucket_t* bucket = &index->buckets[bucket_index];
    
    pthread_mutex_lock(&bucket->mutex);
    
    hash_entry_t* entry = hash_bucket_find(bucket, key, key_size, hash_value);
    
    if (entry) {
        result->found = true;
        result->value = entry->value;
        result->value_size = entry->value_size;
        result->record_id = 0; // Not used in hash index
        index->searches++;
    } else {
        result->found = false;
        result->value = NULL;
        result->value_size = 0;
        result->record_id = 0;
    }
    
    // Update chain traversal statistics
    uint32_t traversals = 0;
    hash_entry_t* temp = bucket->head;
    while (temp && temp != entry) {
        traversals++;
        temp = temp->next;
    }
    if (entry) traversals++; // Count the found entry
    index->chain_traversals += traversals;
    
    pthread_mutex_unlock(&bucket->mutex);
    pthread_rwlock_unlock(&index->resize_lock);
    
    index->total_operations++;
    
    return entry ? INDEX_SUCCESS : INDEX_ERROR_KEY_NOT_FOUND;
}

// Resize operations
bool hash_index_should_resize(hash_index_t* index) {
    double load_factor = (double)index->entry_count / index->bucket_count;
    
    if (load_factor > index->max_load_factor) {
        return true;
    }
    
    // Also check max chain length
    uint32_t max_chain = hash_index_get_max_chain_length(index);
    return max_chain > index->max_chain_length;
}

uint32_t hash_index_next_bucket_count(uint32_t current_count, bool grow) {
    if (grow) {
        return current_count * HASH_INDEX_GROWTH_FACTOR;
    } else {
        return current_count / HASH_INDEX_GROWTH_FACTOR;
    }
}

index_result_t hash_index_resize(hash_index_t* index, uint32_t new_bucket_count) {
    if (atomic_exchange(&index->is_resizing, true)) {
        return INDEX_ERROR_CONCURRENT_UPDATE; // Already resizing
    }
    
    // Create new bucket array
    hash_bucket_t* new_buckets = calloc(new_bucket_count, sizeof(hash_bucket_t));
    if (!new_buckets) {
        atomic_store(&index->is_resizing, false);
        return INDEX_ERROR_OUT_OF_MEMORY;
    }
    
    // Initialize new bucket mutexes
    for (uint32_t i = 0; i < new_bucket_count; i++) {
        if (pthread_mutex_init(&new_buckets[i].mutex, NULL) != 0) {
            for (uint32_t j = 0; j < i; j++) {
                pthread_mutex_destroy(&new_buckets[j].mutex);
            }
            free(new_buckets);
            atomic_store(&index->is_resizing, false);
            return INDEX_ERROR_OUT_OF_MEMORY;
        }
    }
    
    // Rehash all entries
    uint32_t old_bucket_count = index->bucket_count;
    hash_bucket_t* old_buckets = index->buckets;
    
    for (uint32_t i = 0; i < old_bucket_count; i++) {
        pthread_mutex_lock(&old_buckets[i].mutex);
        
        hash_entry_t* entry = old_buckets[i].head;
        while (entry) {
            hash_entry_t* next = entry->next;
            
            // Rehash to new bucket
            uint32_t new_bucket_index = entry->hash_value % new_bucket_count;
            hash_bucket_t* new_bucket = &new_buckets[new_bucket_index];
            
            pthread_mutex_lock(&new_bucket->mutex);
            entry->next = new_bucket->head;
            new_bucket->head = entry;
            new_bucket->count++;
            pthread_mutex_unlock(&new_bucket->mutex);
            
            entry = next;
        }
        
        old_buckets[i].head = NULL;
        old_buckets[i].count = 0;
        pthread_mutex_unlock(&old_buckets[i].mutex);
    }
    
    // Update index
    index->buckets = new_buckets;
    index->bucket_count = new_bucket_count;
    index->rehashes++;
    
    // Destroy old buckets
    for (uint32_t i = 0; i < old_bucket_count; i++) {
        pthread_mutex_destroy(&old_buckets[i].mutex);
    }
    free(old_buckets);
    
    atomic_store(&index->is_resizing, false);
    
    return INDEX_SUCCESS;
}

// Statistics
uint32_t hash_index_get_max_chain_length(hash_index_t* index) {
    uint32_t max_length = 0;
    
    for (uint32_t i = 0; i < index->bucket_count; i++) {
        if (index->buckets[i].count > max_length) {
            max_length = index->buckets[i].count;
        }
    }
    
    return max_length;
}

double hash_index_get_load_factor(hash_index_t* index) {
    return (double)index->entry_count / index->bucket_count;
}

void hash_index_get_stats(hash_index_t* index, index_stats_t* stats) {
    if (!index || !stats) return;
    
    memset(stats, 0, sizeof(index_stats_t));
    
    stats->total_keys = index->entry_count;
    stats->total_operations = index->total_operations;
    stats->searches = index->searches;
    stats->inserts = index->inserts;
    stats->deletes = index->deletes;
    stats->updates = index->updates;
    stats->collisions = index->collisions;
    stats->rehashes = index->rehashes;
    
    // Calculate average chain length
    if (index->entry_count > 0) {
        stats->avg_chain_length = (double)index->entry_count / index->bucket_count;
    }
    
    // Memory usage estimation
    stats->memory_usage = sizeof(hash_index_t) + 
                         index->bucket_count * sizeof(hash_bucket_t) +
                         index->entry_count * sizeof(hash_entry_t);
    
    // Add memory for keys and values (estimation)
    for (uint32_t i = 0; i < index->bucket_count && i < 100; i++) {
        hash_entry_t* entry = index->buckets[i].head;
        while (entry) {
            stats->memory_usage += entry->key_size + entry->value_size;
            entry = entry->next;
        }
    }
}

// Clear operation
index_result_t hash_index_clear(hash_index_t* index) {
    if (!index) return INDEX_ERROR_INVALID_PARAM;
    
    pthread_rwlock_wrlock(&index->resize_lock);
    
    for (uint32_t i = 0; i < index->bucket_count; i++) {
        pthread_mutex_lock(&index->buckets[i].mutex);
        
        hash_entry_t* entry = index->buckets[i].head;
        while (entry) {
            hash_entry_t* next = entry->next;
            hash_entry_destroy(entry, index->memory_mgr);
            entry = next;
        }
        
        index->buckets[i].head = NULL;
        index->buckets[i].count = 0;
        
        pthread_mutex_unlock(&index->buckets[i].mutex);
    }
    
    index->entry_count = 0;
    
    // Reset statistics
    index->total_operations = 0;
    index->searches = 0;
    index->inserts = 0;
    index->deletes = 0;
    index->updates = 0;
    index->collisions = 0;
    index->chain_traversals = 0;
    
    pthread_rwlock_unlock(&index->resize_lock);
    
    return INDEX_SUCCESS;
}

// Validation
bool hash_index_validate(hash_index_t* index) {
    if (!index) return false;
    
    uint32_t counted_entries = 0;
    
    pthread_rwlock_rdlock(&index->resize_lock);
    
    for (uint32_t i = 0; i < index->bucket_count; i++) {
        pthread_mutex_lock(&index->buckets[i].mutex);
        
        uint32_t bucket_count = 0;
        hash_entry_t* entry = index->buckets[i].head;
        
        while (entry) {
            bucket_count++;
            
            // Validate hash placement
            uint32_t expected_bucket = entry->hash_value % index->bucket_count;
            if (expected_bucket != i) {
                pthread_mutex_unlock(&index->buckets[i].mutex);
                pthread_rwlock_unlock(&index->resize_lock);
                return false;
            }
            
            entry = entry->next;
        }
        
        if (bucket_count != index->buckets[i].count) {
            pthread_mutex_unlock(&index->buckets[i].mutex);
            pthread_rwlock_unlock(&index->resize_lock);
            return false;
        }
        
        counted_entries += bucket_count;
        pthread_mutex_unlock(&index->buckets[i].mutex);
    }
    
    pthread_rwlock_unlock(&index->resize_lock);
    
    return counted_entries == index->entry_count;
}

// Hash index iterator implementation
hash_iterator_t* hash_index_iterator_create(hash_index_t* index) {
    if (!index) return NULL;
    
    hash_iterator_t* iter = calloc(1, sizeof(hash_iterator_t));
    if (!iter) return NULL;
    
    iter->index = index;
    iter->current_bucket = 0;
    iter->current_entry = NULL;
    iter->is_valid = false;
    iter->start_key = NULL;
    iter->start_key_size = 0;
    iter->end_key = NULL;
    iter->end_key_size = 0;
    iter->forward = true;
    
    // Find first valid entry
    if (index->entry_count > 0) {
        // Find first non-empty bucket
        for (uint32_t i = 0; i < index->bucket_count; i++) {
            if (index->buckets[i].head != NULL) {
                iter->current_bucket = i;
                iter->current_entry = index->buckets[i].head;
                iter->is_valid = true;
                break;
            }
        }
    }
    
    return iter;
}

bool hash_iterator_valid(hash_iterator_t* iter) {
    if (!iter) return false;
    return iter->is_valid;
}

index_result_t hash_iterator_next(hash_iterator_t* iter) {
    if (!iter || !iter->is_valid) return INDEX_ERROR_INVALID_PARAM;
    
    // Move to next entry in current bucket
    if (iter->current_entry && iter->current_entry->next) {
        iter->current_entry = iter->current_entry->next;
        return INDEX_SUCCESS;
    }
    
    // Move to next non-empty bucket
    for (uint32_t i = iter->current_bucket + 1; i < iter->index->bucket_count; i++) {
        if (iter->index->buckets[i].head != NULL) {
            iter->current_bucket = i;
            iter->current_entry = iter->index->buckets[i].head;
            return INDEX_SUCCESS;
        }
    }
    
    // No more entries
    iter->is_valid = false;
    iter->current_entry = NULL;
    return INDEX_SUCCESS;
}

index_result_t hash_iterator_current(hash_iterator_t* iter,
                                    void** key, size_t* key_size,
                                    void** value, size_t* value_size) {
    if (!iter || !iter->is_valid || !iter->current_entry || !key || !key_size || !value || !value_size) {
        return INDEX_ERROR_INVALID_PARAM;
    }
    
    *key = iter->current_entry->key;
    *key_size = iter->current_entry->key_size;
    *value = iter->current_entry->value;
    *value_size = iter->current_entry->value_size;
    
    return INDEX_SUCCESS;
}

void hash_iterator_destroy(hash_iterator_t* iter) {
    if (!iter) return;
    
    // Note: We don't free start_key and end_key here as they are owned by the caller
    // or are NULL for full scans
    
    free(iter);
}

// Optimized bulk insert operation
index_result_t hash_index_bulk_insert(hash_index_t* index,
                                     const void** keys, size_t* key_sizes,
                                     const void** values, size_t* value_sizes,
                                     size_t count) {
    if (!index || !keys || !key_sizes || !values || !value_sizes || count == 0) {
        return INDEX_ERROR_INVALID_PARAM;
    }
    
    // For optimal performance, we could:
    // 1. Pre-allocate all needed memory
    // 2. Sort the keys by hash value to minimize cache misses
    // 3. Batch operations to reduce lock contention
    // 4. Check if we need to resize first to avoid multiple resizes
    
    // Check if we need to resize based on the new entry count
    uint64_t new_entry_count = index->entry_count + count;
    uint64_t new_bucket_count_needed = (uint64_t)(new_entry_count / index->max_load_factor) + 1;
    
    if (new_bucket_count_needed > index->bucket_count) {
        // Calculate optimal new bucket count
        uint32_t new_bucket_count = index->bucket_count;
        while (new_bucket_count < new_bucket_count_needed) {
            new_bucket_count *= 2;
        }
        
        // Resize before bulk insert for better performance
        index_result_t resize_result = hash_index_resize(index, new_bucket_count);
        if (resize_result != INDEX_SUCCESS) {
            return resize_result;
        }
    }
    
    // Insert all entries
    uint32_t successful_inserts = 0;
    for (size_t i = 0; i < count; i++) {
        if (!keys[i] || !values[i]) {
            continue; // Skip NULL entries
        }
        
        index_result_t result = hash_index_insert(index, keys[i], key_sizes[i], values[i], value_sizes[i]);
        if (result == INDEX_SUCCESS) {
            successful_inserts++;
        } else if (result == INDEX_ERROR_KEY_EXISTS) {
            // Continue with other entries even if some duplicates exist
            continue;
        } else {
            // Serious error, stop processing
            return result;
        }
    }
    
    return (successful_inserts > 0) ? INDEX_SUCCESS : INDEX_ERROR_INVALID_PARAM;
}

index_result_t hash_index_rebuild(hash_index_t* index) {
    // Rebuild is essentially a resize to the same size to defragment
    return hash_index_resize(index, index->bucket_count);
}

// Interface adapter implementations
static index_result_t hash_interface_insert(index_instance_t* index, const void* key, size_t key_size,
                                           const void* value, size_t value_size) {
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    return hash_index_insert(hash_idx, key, key_size, value, value_size);
}

static index_result_t hash_interface_delete(index_instance_t* index, const void* key, size_t key_size) {
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    return hash_index_delete(hash_idx, key, key_size);
}

static index_result_t hash_interface_update(index_instance_t* index, const void* key, size_t key_size,
                                           const void* value, size_t value_size) {
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    return hash_index_update(hash_idx, key, key_size, value, value_size);
}

static index_result_t hash_interface_search(index_instance_t* index, const void* key, size_t key_size,
                                           index_search_result_t* result) {
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    return hash_index_search(hash_idx, key, key_size, result);
}

static index_iterator_t* hash_interface_range_scan(index_instance_t* index, 
                                                  const void* start_key, size_t start_key_size,
                                                  const void* end_key, size_t end_key_size,
                                                  bool forward) {
    // Hash indexes don't support range scans efficiently
    return NULL;
}

static bool hash_interface_iterator_valid(index_iterator_t* iter) {
    return hash_iterator_valid((hash_iterator_t*)iter->internal_state);
}

static index_result_t hash_interface_iterator_next(index_iterator_t* iter) {
    return hash_iterator_next((hash_iterator_t*)iter->internal_state);
}

static index_result_t hash_interface_iterator_current(index_iterator_t* iter, 
                                                     void** key, size_t* key_size,
                                                     void** value, size_t* value_size) {
    return hash_iterator_current((hash_iterator_t*)iter->internal_state, 
                                key, key_size, value, value_size);
}

static void hash_interface_iterator_destroy(index_iterator_t* iter) {
    if (iter) {
        hash_iterator_destroy((hash_iterator_t*)iter->internal_state);
        free(iter);
    }
}

static index_result_t hash_interface_bulk_insert(index_instance_t* index, 
                                                const void** keys, size_t* key_sizes,
                                                const void** values, size_t* value_sizes,
                                                size_t count) {
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    return hash_index_bulk_insert(hash_idx, keys, key_sizes, values, value_sizes, count);
}

static size_t hash_interface_range_delete(index_instance_t* index,
                                         const void* start_key, size_t start_key_size,
                                         const void* end_key, size_t end_key_size) {
    // Hash indexes don't support efficient range deletes
    return 0;
}

static index_result_t hash_interface_clear(index_instance_t* index) {
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    return hash_index_clear(hash_idx);
}

static index_result_t hash_interface_rebuild(index_instance_t* index) {
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    return hash_index_rebuild(hash_idx);
}

static void hash_interface_destroy(index_instance_t* index) {
    if (index && index->index_data) {
        hash_index_t* hash_idx = (hash_index_t*)index->index_data;
        hash_index_destroy(hash_idx);
        
        pthread_rwlock_destroy(&index->rwlock);
        free(index);
    }
}

static void hash_interface_get_stats(index_instance_t* index, index_stats_t* stats) {
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    hash_index_get_stats(hash_idx, stats);
}

static bool hash_interface_validate(index_instance_t* index) {
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    return hash_index_validate(hash_idx);
}

static index_result_t hash_interface_set_config(index_instance_t* index, const index_config_t* config) {
    if (!index || !config) return INDEX_ERROR_INVALID_PARAM;
    
    hash_index_t* hash_idx = (hash_index_t*)index->index_data;
    
    // Update configurable parameters
    if (config->load_factor > 0.0 && config->load_factor < 1.0) {
        hash_idx->max_load_factor = config->load_factor;
    }
    
    index->config = *config;
    return INDEX_SUCCESS;
}

static void hash_interface_get_config(index_instance_t* index, index_config_t* config) {
    if (index && config) {
        *config = index->config;
    }
}

// Factory function to create hash index interface
index_interface_t* hash_index_interface_create(void) {
    index_interface_t* interface = malloc(sizeof(index_interface_t));
    if (!interface) return NULL;
    
    interface->insert = hash_interface_insert;
    interface->delete = hash_interface_delete;
    interface->update = hash_interface_update;
    interface->search = hash_interface_search;
    interface->range_scan = hash_interface_range_scan;
    interface->iterator_valid = hash_interface_iterator_valid;
    interface->iterator_next = hash_interface_iterator_next;
    interface->iterator_current = hash_interface_iterator_current;
    interface->iterator_destroy = hash_interface_iterator_destroy;
    interface->bulk_insert = hash_interface_bulk_insert;
    interface->range_delete = hash_interface_range_delete;
    interface->clear = hash_interface_clear;
    interface->rebuild = hash_interface_rebuild;
    interface->destroy = hash_interface_destroy;
    interface->get_stats = hash_interface_get_stats;
    interface->validate = hash_interface_validate;
    interface->set_config = hash_interface_set_config;
    interface->get_config = hash_interface_get_config;
    
    return interface;
}

// Extended factory function that creates both interface and index instance
index_instance_t* hash_index_instance_create(memory_manager_t* memory_mgr, 
                                            const char* name,
                                            const index_config_t* config) {
    if (!memory_mgr || !name || !config) return NULL;
    
    // Create the hash index
    uint32_t bucket_count = config->bucket_count > 0 ? config->bucket_count : HASH_INDEX_DEFAULT_BUCKETS;
    double load_factor = config->load_factor > 0.0 ? config->load_factor : HASH_INDEX_MAX_LOAD_FACTOR;
    
    hash_index_t* hash_idx = hash_index_create(memory_mgr, bucket_count, load_factor);
    if (!hash_idx) return NULL;
    
    // Create the index instance
    index_instance_t* instance = malloc(sizeof(index_instance_t));
    if (!instance) {
        hash_index_destroy(hash_idx);
        return NULL;
    }
    
    memset(instance, 0, sizeof(index_instance_t));
    
    // Initialize instance
    instance->type = INDEX_TYPE_HASH;
    instance->interface = hash_index_interface_create();
    instance->index_data = hash_idx;
    instance->config = *config;
    instance->memory_mgr = memory_mgr;
    strncpy(instance->name, name, sizeof(instance->name) - 1);
    
    if (pthread_rwlock_init(&instance->rwlock, NULL) != 0) {
        free(instance->interface);
        hash_index_destroy(hash_idx);
        free(instance);
        return NULL;
    }
    
    atomic_init(&instance->is_destroyed, false);
    
    return instance;
}